﻿using System;
using PostSharp.Laos;
using TestBat.IModels.Exceptions;
using TestBat.Models.Exceptions;
using TestBat.ServiceLocator;
using uNhAddIns.SessionEasier.Conversations;

namespace TestBat.Models.Attributes
{
    public enum ConversationEndMode
    {
        ///<summary>
        /// Continue the conversation
        ///</summary>
        Continue,
        /// <summary>
        /// Commit and continue the conversation
        /// </summary>
        CommitAndContinue
    }

    [Serializable]
    public class ConversationAttribute : OnMethodBoundaryAspect
    {
        public ConversationAttribute()
            : this(ConversationEndMode.Continue)
        {
        }

        public ConversationAttribute(ConversationEndMode endMode)
        {
            this.endMode = endMode;
        }

        public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
            IConversation c = DefaultServiceLocator.Get<IConversation>();
            c.Resume();
        }

        public override void OnSuccess(MethodExecutionEventArgs eventArgs)
        {
            try
            {
                //string convId = GetConversationId();
                IConversation c = DefaultServiceLocator.Get<IConversation>();
                switch (endMode)
                {
                    case ConversationEndMode.CommitAndContinue:
                        c.FlushAndPause();
                        break;
                    default:
                        c.Pause();
                        break;
                }
            }
            catch (Exception e)
            { // an exception occurred during conversation handling, dispatch to OnException handler
                eventArgs.Exception = e;
                OnException(eventArgs);
            }
        }

        public override void OnException(MethodExecutionEventArgs eventArgs)
        {
            if (eventArgs.Exception is IValidationException || eventArgs.Exception is IDatabaseException)
            { // pass on to next layer
                eventArgs.FlowBehavior = FlowBehavior.RethrowException;
            }
            else
            { // wrap other exceptions in BusinessException and dispose conversation
                IConversation c = DefaultServiceLocator.Get<IConversation>();
                // TODO: conversation needs to be removed from the container (ID needed)

                if (c != null)
                {
                    c.Dispose();
                }

                eventArgs.FlowBehavior = FlowBehavior.Continue;
                throw new BusinessException("Method failed", eventArgs.Exception);
            }
        }

        private readonly ConversationEndMode endMode;
    }
}
